<?php
/**
 *	KLF Framework
 *
 *	Written by Kristian Oye <kristianoye@gmail.com> on Oct 22, 2011
 *	Copyright (C) 2010-2011
 */
namespace KLF\System\Web
{
	use KLF\KCore;
	use KLF\System\IDisposable;
	use KLF\System\KApplication;
	use KLF\System\Cache\ICache;
	use KLF\System\Cache\KFakeCache;
	use KLF\System\Errors\KException;
	use KLF\System\Errors\KExceptionHandler;
	use KLF\System\Web\Events\KApplicationRun;
	use KLF\System\Web\Events\KApplicationLoad;
	use KLF\System\Web\Events\KApplicationStart;
	use KLF\System\Web\Events\KApplicationUnload;
	use KLF\System\Web\Responses\KStandardResponse;
	use KLF\System\Config\KApplicationConfiguration;
	use KLF\System\Web\Events\KApplicationInitialize;
	use KLF\System\Web\Responses\Model\KExceptionModel;
	
	/**
	 *  Class KHttpApplication
	 *
	 *  The base for all web applications.
	 *  
	 *  @property ICache $Cache
	 *  @property KHttpContext $Context The application's current execution context.
	 *  
	 *  @property \KLF\System\Web\Events\KApplicationInitialize $eventInitialized The initialization event.
	 *  @property \KLF\System\Web\Events\KApplicationRun $eventRun The run event.
	 *  @property \KLF\System\Web\Events\KApplicationStart $eventStart The event that fires when the application is starting a request.
	 *  @property \KLF\System\Web\Events\KApplicationUnload $eventUnload The application has finished processing the request.
	 *  @property \KLF\System\Web\Events\KPostMapRequestHandler $eventPostMapRequestHandler
	 *  @property \KLF\System\Web\Events\KPostResolveRequestCache $eventPostMapRequestHandler
	 *  @property \KLF\System\Errors\KExceptionHandler $ExceptionHandler
	 *  
	 *  @method mixed eventFinished()
	 *  @method mixed eventInitialized()
	 *  @method mixed eventStartup()
	 *  @method mixed eventUnload()
	 *  
	 *  @method KHttpApplication NewInstance
	 *  
	 *  @package KLF\System\Web
	 *  @access public
	 *  @author Kristian Oye <kristianoye@gmail.com>
	 *  
	 */
	abstract class KHttpApplication extends KApplication implements IHttpHandler, IDisposable
	{
		/**
		 * The event that fires when the application initializes.
		 * 
		 * @var \KLF\System\Web\Events\KAppInitialized $_eventInitialize
		 */
		protected $_eventInitialize;

		/**
		 * @var \KLF\System\Web\Events\KPostMapRequestHandler $_eventPostMapRequestHandler
		 */
		protected $_eventPostMapRequestHandler;
		
		/**
		 * @var \KLF\System\Web\Events\KPostResolveRequestCache $_eventPostResolveRequestCache
		 */
		protected $_eventPostResolveRequestCache;
		
		/**
		 * The event that fires when the application runs.
		 * 
		 * @var \KLF\System\Web\Events\KApplicationRun $_eventRun
		 */
		protected $_eventRun;
		
		/**
		 * The event that fires when the application starts up.
		 * 
		 * @var \KLF\System\Web\Events\KApplicationStart $_eventStart
		 */
		protected $_eventStart;
		
		/**
		 * The event that fires when execution is complete.
		 * @var \KLF\System\Web\Events\KApplicationUnload $_eventFinished
		 */
		protected $_eventUnload;
		
		/**
		 * The object that handles any exceptions.
		 * 
		 * @var \KLF\System\Errors\KExceptionHandler $_rpropErrorHandler
		 */
		protected $_rpropExceptionHandler;
		
		/**
		 * 
		 * @var ICache $_rpropCache
		 */
		protected $_rpropCache;
		
		/**
		 * The handler reponsible for dispatching the request.
		 * 
		 * @var IHttpHandler $_rpropHandler
		 */
		protected $_rpropHandler;
		
		/**
		 * The context that is currently executing.
		 * 
		 * @var KHttpContext $_rpropContext
		 */
		protected $_rpropContext;
		
		/**
		 * Construct a new web application.
		 *
		 * @author Kristian Oye <kristianoye@gmail.com>
		 * @since 0.1
		*/
		public function __construct(KApplicationConfiguration $config)
		{
			$this->_eventInitialize = new KApplicationInitialize();
			$this->_eventRun = new KApplicationRun();
			$this->_eventStart = new KApplicationStart();
			$this->_eventUnload = new KApplicationUnload();
			
			$this->_rpropCache = $config->GetValue('Caching', new KFakeCache());
			
			parent::__construct($config);
		}
		
		/**
		 * Any cleenup code should go here.
		 * 
		 * (non-PHPdoc)
		 * @see KLF\System.IDisposable::Dispose()
		 */
		public function Dispose()
		{
			unset($this->_rpropCache);
		}
		
		/**
		 * Returns true if this object can be re-used.
		 * 
		 * (non-PHPdoc)
		 * @see KLF\System\Web.IHttpHandler::GetIsReusable()
		 */
		public function GetIsReusable()
		{
			return false;
		}
		
		/**
		* Add the header to the Response.
		 */
		public function GetVersionHeader()
		{
			return KCore::GetVersion();
		}
		
		/**
		* Header that gets added to indicate the framework version.
		 *
		* @return string
		*/
		public function GetVersionHeaderName()
		{
			return 'X-PHP-KLF-Version';
		}
				
		/**
		 * Takes care of the initialization process
		 * <ul>
		 * <li>Create the current HTTP Context.</li>
		 * <li>Create a helper object.</li>
		 * <li>Create a cache object from the config.</li>
		 * </ul>
		 */
		protected function Initialize()
		{
			$this->_rpropContext = new KHttpContext($this);

			$cache = $this->Config->GetValue('Caching');
			$this->_rpropCache = $cache->Initialize();
			
			$this->Context->Response->BufferOutput = true;
			$this->Context->Response->Headers->Add(
					$this->GetVersionHeaderName(), 
					sprintf("%.2f", $this->GetVersionHeader()));
			
			$this->eventInitialize();
		}
		
		/**
		 * Implementation of IHttpHandler interface.
		 * 
		 * @param unknown_type $context
		 */
		public function ProcessRequest(KHttpContext $context)
		{
			$handler = $context->Handler;
			
			$handler->ProcessRequest($this->Context);
		}
		
		/**
		 * Dispatch the request.
		 */
		protected function RunApplication()
		{
			$this->ProcessRequest($this->Context);
			$this->eventRun();
		}

		/**
		 * Called just before the application enters the run state.
		 */
		protected function StartApplication()
		{
			$this->eventStart();
		}
		
		/**
		 * Called when the application has finished running.
		 */
		protected function UnloadApplication()
		{
			$this->eventUnload();
		}
		
		/**
		 * Begin the KLF page cycle:<ol>
		 * 	<li>Initialize application.</li>
		 *	<li>Start the application.</li>
		 *  <li>Run the application to process current request.</li>
		 *  <li>Shut the application down and return the result.</li>
		 *  </ol>			
		 * @see KLF\System.KApplication::Run()
		 */
		public function Run()
		{
			try
			{
				parent::Run();
				
				$this->Initialize();
				$this->StartApplication();
				$this->RunApplication();
				$this->UnloadApplication();
			}
			catch(\Exception $ex)
			{
				if (isset($this->_rpropErrorHandler))
				{
					$this->_rpropExceptionHandler->HandleException($ex);
				}
				else 
				{
					KStandardResponse::Render(500, new KExceptionModel($ex));
				}
			}
		}
	}
}
